﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Speech.Recognition;
using System.Windows;
using System.Windows.Threading;
using AgilePlannerDT.Data;
using AgilePlannerDT.Data.Impl;
using AgilePlannerDT.Display;
using AgilePlannerDT.Utils;
using System.Globalization;

namespace AgilePlannerDT.Application.Modules.Impl
{
    public class SpeechModuleImpl : AbstractApplicationModule, SpeechModule
    {
        protected SpeechRecognizer sharedRecognizer;
        public static readonly string CREATE_STORYCARD_COMMAND = "create storycard";
        public static readonly string CREATE_ITERATION_COMMAND = "create iteration";
        public static readonly string HIGHLIGHT_COMMAND = "highlight";
        public static readonly string SELECT_COMMAND = "select";
        public static readonly string DELETE_COMMAND = "delete card";
        public static readonly string NEXT_COMMAND = "next card";
        public static readonly string PREVIOUS_COMMAND = "previous card";
        public static readonly string DICTATION_COMMAND = "start dictation";

        protected bool selectionEnabled = false;


        public SpeechModuleImpl(AgilePlannerApplication app, Dispatcher dispatcher)
        {
            this.app = app;
            this.dispatcher = dispatcher;

            sharedRecognizer = new SpeechRecognizer();
            sharedRecognizer.AudioLevelUpdated += new EventHandler<AudioLevelUpdatedEventArgs>(sharedRecognizer_AudioLevelUpdated);
            sharedRecognizer.AudioSignalProblemOccurred += new EventHandler<AudioSignalProblemOccurredEventArgs>(sharedRecognizer_AudioSignalProblemOccurred);
            sharedRecognizer.AudioStateChanged += new EventHandler<AudioStateChangedEventArgs>(sharedRecognizer_AudioStateChanged);
            sharedRecognizer.EmulateRecognizeCompleted += new EventHandler<EmulateRecognizeCompletedEventArgs>(sharedRecognizer_EmulateRecognizeCompleted);
            sharedRecognizer.LoadGrammarCompleted += new EventHandler<LoadGrammarCompletedEventArgs>(sharedRecognizer_LoadGrammarCompleted);
            sharedRecognizer.RecognizerUpdateReached += new EventHandler<RecognizerUpdateReachedEventArgs>(sharedRecognizer_RecognizerUpdateReached);
            sharedRecognizer.SpeechDetected += new EventHandler<SpeechDetectedEventArgs>(sharedRecognizer_SpeechDetected);
            sharedRecognizer.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(sharedRecognizer_SpeechHypothesized);
            sharedRecognizer.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(sharedRecognizer_SpeechRecognitionRejected);
            sharedRecognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(sharedRecognizer_SpeechRecognized);
            sharedRecognizer.StateChanged += new EventHandler<System.Speech.Recognition.StateChangedEventArgs>(sharedRecognizer_StateChanged);

            sharedRecognizer.Enabled = true;
            sharedRecognizer.UnloadAllGrammars();

            GrammarBuilder gb = new GrammarBuilder(GetCommandChoices());

            //if you are using WinXP the speech recognition only works with english
            gb.Culture = CultureInfo.CreateSpecificCulture("en-US");

            Grammar commandsGrammar = new Grammar(gb);
            commandsGrammar.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(commandsGrammar_SpeechRecognized);

            sharedRecognizer.LoadGrammar(commandsGrammar);
        }

        //private Grammar CreateGrammarBuilderRGBSemantics2(params int[] info)
        //{
        //    //Create a set of choices, each a lookup from a color name to rgb
        //    //Choices constructors do not take SematicResultValue, so cast SematicResultValue to GramarBuilder
        //    Choices colorChoice = new Choices();
        //    foreach (string colorName in System.Enum.GetNames(typeof(KnownColor)))
        //    {
        //        SemanticResultValue choiceResultValue = new SemanticResultValue(colorName, Color.FromName(colorName).ToArgb());
        //        GrammarBuilder resultValueBuilder = new GrammarBuilder(choiceResultValue);
        //        colorChoice.Add(resultValueBuilder);
        //    }

        //    SemanticResultKey choiceResultKey = new SemanticResultKey("rgb", colorChoice);
        //    GrammarBuilder choiceBuilder = new GrammarBuilder(choiceResultKey);
        //    //Create two intermediate grammars with introductory phrase and the color choice
        //    GrammarBuilder makeBackgroundBuilder = "Make background";
        //    makeBackgroundBuilder.Append(choiceBuilder);

        //    GrammarBuilder configureBackgroundBuilder = new GrammarBuilder("Configure background as");
        //    configureBackgroundBuilder.Append(new SemanticResultKey("rgb", colorChoice));

        //    //Createthefinalgrammarrecognizingeitherintermediategrammar//BycreatingachoicefrombothGrammarBuildersabove//ThenconstructingaGrammarBuilderfromthatchoice//Thenconstructingthegrammar.ChoicesbothChoices=newChoices(makeBackgroundBuilder,configureBackgroundBuilder);GrammarBuilderbothBuilder=newGrammarBuilder(bothChoices);Grammargrammar=newGrammar(bothBuilder);
        //    grammar.Name = "Make Background /Configure background as";
        //    return grammar;
        //}


        #region Speech

        private void commandsGrammar_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            TextRecognized(e.Result.Text);
        }

        public void TextRecognized(string arg)
        {
            if (arg.Equals(CREATE_ITERATION_COMMAND))
            {
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new CreateIterationDelegate(CreateIteration));
            }
            else if (arg.Equals(CREATE_STORYCARD_COMMAND))
            {
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new CreateStoryCardDelegate(CreateStoryCard));
            }
            else if (arg.Equals(DELETE_COMMAND))
            {
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new DeleteDelegate(Delete));
            }
            else if (arg.Equals(HIGHLIGHT_COMMAND))
            {
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new HighlightDelegate(Highlight));
            }
            else if (arg.Equals(NEXT_COMMAND))
            {
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new NextDelegate(Next));
            }
            else if (arg.Equals(PREVIOUS_COMMAND))
            {
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new PreviousDelegate(Previous));
            }
            else if (arg.Equals(SELECT_COMMAND))
            {
                selectionEnabled = true;
                ApplicationDispatcher.Invoke(DispatcherPriority.Render, new HighlightDelegate(Highlight));
            }
            else if (arg.Equals(DICTATION_COMMAND))
            {
            }
        }

        private delegate void DeleteDelegate();
        public void Delete()
        {
            Application.Delete();
        }

        private delegate void PreviousDelegate();
        public void Previous()
        {
            Application.Previous();
        }

        private delegate void NextDelegate();
        public void Next()
        {
            Application.Next();
        }

        private delegate void CreateIterationDelegate();
        public void CreateIteration()
        {
            Iteration iter = new IterationDataObject();

            Point ctr = new Point(Application.GetWidth() / 2, Application.GetHeight() / 2);

            iter.LocationX = ctr.X - iter.Width / 2;
            iter.LocationY = ctr.Y - iter.Height / 2;

            Application.Persister.CreateIteration(iter.Name, iter.Description, (int)iter.Width, (int)iter.Height, (int)iter.LocationX, (int)iter.LocationY, (float)iter.AvailableEffort, iter.StartDate, iter.EndDate);
        }


        private delegate void CreateStoryCardDelegate();
        public void CreateStoryCard()
        {
            if (Application.Project == null)
            {
                MessageBox.Show("Cannot create story card. Please connected to a project first.", "Error");
            }
            else
            {
                StoryCard sc = new StoryCardDataObject();

                Point ctr = new Point(Application.GetWidth() / 2, Application.GetHeight() / 2);

                IterationDisplayObject iter;
                long pid = Application.Project.Backlog.ID;

                if (Application.TryFindIteration(ctr, out iter))
                {
                    pid = iter.ID;
                }

                sc.LocationX = ctr.X - sc.Width / 2;
                sc.LocationY = ctr.Y - sc.Height / 2;
                sc.Parent = pid;


                Application.Persister.CreateStoryCard(sc.Name, sc.Description, (int)sc.Width, (int)sc.Height, (int)sc.LocationX, (int)sc.LocationY, sc.Parent, (float)sc.BestCaseEstimate, (float)sc.MostlikelyEstimate, (float)sc.WorstCaseEstimate, (float)sc.ActualEffort, sc.Status, (string)new CardColorConverter().ConvertTo(Application.DefaultColor, typeof(string)), sc.CardOwner, (float)sc.RotationAngle);
            }
        }

        private delegate void HighlightDelegate();
        public void Highlight()
        {
            Application.Highlight();
        }

        private Choices GetCommandChoices()
        {
            Choices cc = new Choices();

            cc.Add(CREATE_ITERATION_COMMAND,
                CREATE_STORYCARD_COMMAND,
                DELETE_COMMAND,
                HIGHLIGHT_COMMAND,
                NEXT_COMMAND,
                PREVIOUS_COMMAND,
                SELECT_COMMAND);

            return cc;
        }

        private Choices GetNumberChoices()
        {
            Choices nc = new Choices();

            for (int i = 1; i < 150; i++)
            {
                nc.Add(i.ToString());
            }

            return nc;
        }

        private Choices GetIndexCardColorChoices()
        {
            Choices cc = new Choices();

            cc.Add(CardConstants.CardColors.aqua.ToString(),
                CardConstants.CardColors.blue.ToString(),
                CardConstants.CardColors.gray.ToString(),
                CardConstants.CardColors.green.ToString(),
                CardConstants.CardColors.khaki.ToString(),
                CardConstants.CardColors.peach.ToString(),
                CardConstants.CardColors.pink.ToString(),
                CardConstants.CardColors.red.ToString(),
                CardConstants.CardColors.white.ToString(),
                CardConstants.CardColors.yellow.ToString());

            return cc;
        }


        public void Unload()
        {
            sharedRecognizer.UnloadAllGrammars();
        }

        public void Disable()
        {
            sharedRecognizer.Enabled = false;
        }

        public void Enable()
        {
            sharedRecognizer.Enabled = true;
        }

        private void sharedRecognizer_StateChanged(object sender, System.Speech.Recognition.StateChangedEventArgs e)
        {
            System.Console.WriteLine("StateChanged : " + e.RecognizerState.ToString());
        }

        private void sharedRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            System.Console.WriteLine("SpeechRecognized : " + e.Result.Text);
        }

        private void sharedRecognizer_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            System.Console.WriteLine("SpeechRecognitionRejected : " + e.Result.Text);
        }

        private void sharedRecognizer_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            System.Console.WriteLine("SpeechHypothesized : " + e.Result.Text);
        }

        private void sharedRecognizer_SpeechDetected(object sender, SpeechDetectedEventArgs e)
        {
            System.Console.WriteLine("SpeechDetected : " + e.AudioPosition.TotalMilliseconds.ToString());
        }

        private void sharedRecognizer_RecognizerUpdateReached(object sender, RecognizerUpdateReachedEventArgs e)
        {
            System.Console.WriteLine("RecognizerUpdateReached : " + e.AudioPosition.TotalMilliseconds.ToString());
        }

        private void sharedRecognizer_LoadGrammarCompleted(object sender, LoadGrammarCompletedEventArgs e)
        {
            System.Console.WriteLine("LoadGrammarCompleted : " + e.Grammar.Name);
        }

        private void sharedRecognizer_EmulateRecognizeCompleted(object sender, EmulateRecognizeCompletedEventArgs e)
        {
            if (e.Result != null)
            {
                System.Console.WriteLine("EmulateRecognizeCompleted : " + e.Result.Text);
            }
            else
            {
                System.Console.WriteLine("EmulateRecognizeCompleted : null result");
            }
        }

        private void sharedRecognizer_AudioStateChanged(object sender, AudioStateChangedEventArgs e)
        {
           // System.Console.WriteLine("AudioStateChanged : " + e.AudioState.ToString());
        }

        private void sharedRecognizer_AudioSignalProblemOccurred(object sender, AudioSignalProblemOccurredEventArgs e)
        {
            //System.Console.WriteLine("AudioSignalProblemOccurred : " + e.AudioSignalProblem.ToString());
        }

        private void sharedRecognizer_AudioLevelUpdated(object sender, AudioLevelUpdatedEventArgs e)
        {
            //System.Console.WriteLine("AudioLevelUpdated : " + e.AudioLevel.ToString());
        }

        #endregion
    }
}
